      //--------------------------------------------------------------
        // Copyright (C) 2006 Michael Schwarz (http://www.ajaxpro.info).
        // All rights reserved.
        //--------------------------------------------------------------

        // core.js
        Object.extend(Function.prototype, {
          getArguments: function() {
            var args = [];
            for(var i=0; i<this.arguments.length; i++) {
              args.push(this.arguments[i]);
            }
            return args;
          }
        }, false);

        var MS = {"Browser":{}};

        Object.extend(MS.Browser, {
          isIE: navigator.userAgent.indexOf('MSIE') != -1,
          isFirefox: navigator.userAgent.indexOf('Firefox') != -1,
          isOpera: window.opera != null
        }, false);

        var AjaxPro = {};

        AjaxPro.IFrameXmlHttp = function() {};
        AjaxPro.IFrameXmlHttp.prototype = {
          onreadystatechange: null, headers: [], method: "POST", url: null, async: true, iframe: null,
          status: 0, readyState: 0, responseText: null,
          abort: function() {
          },
          readystatechanged: function() {
            var doc = this.iframe.contentDocument || this.iframe.document;
            if(doc != null && doc.readyState == "complete" && doc.body != null && doc.body.res != null) {
              this.status = 200;
              this.statusText = "OK";
              this.readyState = 4;
              this.responseText = doc.body.res;
              this.onreadystatechange();
              return;
            }
            setTimeout(this.readystatechanged.bind(this), 10);
          },
          open: function(method, url, async) {
            if(async == false) {
              alert("Synchronous call using IFrameXMLHttp is not supported.");
              return;
            }
            if(this.iframe == null) {
              var iframeID = "hans";
              if (document.createElement && document.documentElement &&
                (window.opera || navigator.userAgent.indexOf('MSIE 5.0') == -1))
              {
                var ifr = document.createElement('iframe');
                ifr.setAttribute('id', iframeID);
                ifr.style.visibility = 'hidden';
                ifr.style.position = 'absolute';
                ifr.style.width = ifr.style.height = ifr.borderWidth = '0px';

                this.iframe = document.getElementsByTagName('body')[0].appendChild(ifr);
              }
              else if (document.body && document.body.insertAdjacentHTML)
              {
                document.body.insertAdjacentHTML('beforeEnd', '<iframe name="' + iframeID + '" id="' + iframeID + '" style="border:1px solid black;display:none"></iframe>');
              }
              if (window.frames && window.frames[iframeID]) {
                this.iframe = window.frames[iframeID];
              }
              this.iframe.name = iframeID;
              this.iframe.document.open();
              this.iframe.document.write("<"+"html><"+"body></"+"body></"+"html>");
              this.iframe.document.close();
            }
            this.method = method;
            this.url = url;
            this.async = async;
          },
          setRequestHeader: function(name, value) {
            for(var i=0; i<this.headers.length; i++) {
              if(this.headers[i].name == name) {
                this.headers[i].value = value;
                return;
              }
            }
            this.headers.push({"name":name,"value":value});
          },
          getResponseHeader: function(name, value) {
            return null;
          },
          addInput: function(doc, form, name, value) {
            var ele;
            var tag = "input";
            if(value.indexOf("\n") >= 0) {
              tag = "textarea";
            }

            if(doc.all) {
              ele = doc.createElement("<" + tag + " name=\"" + name + "\" />");
            }else{
              ele = doc.createElement(tag);
              ele.setAttribute("name", name);
            }
            ele.setAttribute("value", value);
            form.appendChild(ele);
            ele = null;
          },
          send: function(data) {
            if(this.iframe == null) {
              return;
            }
            var doc = this.iframe.contentDocument || this.iframe.document;
            var form = doc.createElement("form");

            doc.body.appendChild(form);

            form.setAttribute("action", this.url);
            form.setAttribute("method", this.method);
            form.setAttribute("enctype", "application/x-www-form-urlencoded");

            for(var i=0; i<this.headers.length; i++) {
              switch(this.headers[i].name.toLowerCase()) {
                case "content-length":
                case "accept-encoding":
                case "content-type":
                  break;
                default:
                  this.addInput(doc, form, this.headers[i].name, this.headers[i].value);
              }
            }
            this.addInput(doc, form, "data", data);
            form.submit();

            setTimeout(this.readystatechanged.bind(this), 0);
          }
        };

        var progids = ["Msxml2.XMLHTTP.6.0", "Msxml2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"];
        var progid = null;

        if(typeof ActiveXObject != "undefined") {
          var ie7xmlhttp = false;
          if(typeof XMLHttpRequest == "object") {
            try{ var o = new XMLHttpRequest(); ie7xmlhttp = true; }catch(e){}
          }
          if(typeof XMLHttpRequest == "undefined" || !ie7xmlhttp) {
            XMLHttpRequest = function() {
              var xmlHttp = null;
              if(!AjaxPro.noActiveX) {
                if(progid != null) {
                  return new ActiveXObject(progid);
                }
                for(var i=0; i<progids.length && xmlHttp == null; i++) {
                  try {
                    xmlHttp = new ActiveXObject(progids[i]);
                    progid = progids[i];

                  }catch(e){}
                }
              }
              if(xmlHttp == null && MS.Browser.isIE) {
                return new AjaxPro.IFrameXmlHttp();
              }
              return xmlHttp;
            };
          }
        }

        Object.extend(AjaxPro, {
          noOperation: function() {},
          onLoading: function() {},
          onError: function() {},
          onTimeout: function() { return true; },
          onStateChanged: function() {},
          cryptProvider: null,
          queue: null,
          token: "",
          version: "9.2.17.1",
          ID: "AjaxPro",
          noActiveX: false,
          timeoutPeriod: 15*1000,
          queue: null,
          noUtcTime: false,
          regExDate: function(str,p1, p2,offset,s) {
                str = str.substring(1).replace('"','');
                var date = str;

                if (str.substring(0,7) == "\\\/Date(") {
                    str = str.match(/Date\((.*?)\)/)[1];
                    date = "new Date(" +  parseInt(str) + ")";
                }
                else { // ISO Date 2007-12-31T23:59:59Z
                    var matches = str.split( /[-,:,T,Z]/);
                    matches[1] = (parseInt(matches[1],0)-1).toString();
                    date = "new Date(Date.UTC(" + matches.join(",") + "))";
               }
                return date;
            },
            parse: function(text) {
            // not yet possible as we still return new type() JSON
        //    if (!(!(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
        //    text.replace(/"(\\.|[^"\\])*"/g, '')))  ))
        //      throw new Error("Invalid characters in JSON parse string.");

                var regEx = /(\"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}.*?\")|(\"\\\/Date\(.*?\)\\\/")/g;
                text = text.replace(regEx,this.regExDate);

                return eval('(' + text + ')');
            },
          m : {
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
          },
          toJSON: function(o) {
            if(o == null) {
              return "null";
            }
            var v = [];
            var i;
            var c = o.constructor;
            if(c == Number) {
              return isFinite(o) ? o.toString() : AjaxPro.toJSON(null);
            } else if(c == Boolean) {
              return o.toString();
            } else if(c == String) {
              if (/["\\\x00-\x1f]/.test(o)) {
                o = o.replace(/([\x00-\x1f\\"])/g, function(a, b) {
                  var c = AjaxPro.m[b];
                  if (c) {
                    return c;
                  }
                  c = b.charCodeAt();
                  return '\\u00' +
                    Math.floor(c / 16).toString(16) +
                    (c % 16).toString(16);
                });
                    }
              return '"' + o + '"';
            } else if (c == Array) {
              for(i=0; i<o.length; i++) {
                v.push(AjaxPro.toJSON(o[i]));
              }
              return "[" + v.join(",") + "]";
            } else if (c == Date) {
        //      var d = {};
        //      d.__type = "System.DateTime";
        //      if(AjaxPro.noUtcTime == true) {
        //        d.Year = o.getFullYear();
        //        d.Month = o.getMonth() +1;
        //        d.Day = o.getDate();
        //        d.Hour = o.getHours();
        //        d.Minute = o.getMinutes();
        //        d.Second = o.getSeconds();
        //        d.Millisecond = o.getMilliseconds();
        //      } else {
        //        d.Year = o.getUTCFullYear();
        //        d.Month = o.getUTCMonth() +1;
        //        d.Day = o.getUTCDate();
        //        d.Hour = o.getUTCHours();
        //        d.Minute = o.getUTCMinutes();
        //        d.Second = o.getUTCSeconds();
        //        d.Millisecond = o.getUTCMilliseconds();
        //      }
              return AjaxPro.toJSON("/Date(" + new Date(Date.UTC(o.getUTCFullYear(), o.getUTCMonth(), o.getUTCDate(), o.getUTCHours(), o.getUTCMinutes(), o.getUTCSeconds(), o.getUTCMilliseconds())).getTime() + ")/");
            }
            if(typeof o.toJSON == "function") {
              return o.toJSON();
            }
            if(typeof o == "object") {
              for(var attr in o) {
                if(typeof o[attr] != "function") {
                  v.push('"' + attr + '":' + AjaxPro.toJSON(o[attr]));
                }
              }
              if(v.length>0) {
                return "{" + v.join(",") + "}";
              }
              return "{}";
            }
            return o.toString();
          },
          dispose: function() {
            if(AjaxPro.queue != null) {
              AjaxPro.queue.dispose();
            }
          }
        }, false);

        addEvent(window, "unload", AjaxPro.dispose);

        AjaxPro.Request = function(url) {
          this.url = url;
          this.xmlHttp = null;
        };

        AjaxPro.Request.prototype = {
          url: null,
          callback: null,
          onLoading: null,
          onError: null,
          onTimeout: null,
          onStateChanged: null,
          args: null,
          context: null,
          isRunning: false,
          abort: function() {
            if(this.timeoutTimer != null) {
              clearTimeout(this.timeoutTimer);
            }
            if(this.xmlHttp) {
              this.xmlHttp.onreadystatechange = AjaxPro.noOperation;
              this.xmlHttp.abort();
            }
            if(this.isRunning) {
              this.isRunning = false;
              this.onLoading(false);
            }
          },
          dispose: function() {
            this.abort();
          },
          getEmptyRes: function() {
            return {
              error: null,
              value: null,
              request: {method:this.method, args:this.args},
              context: this.context,
              duration: this.duration
            };
          },
          endRequest: function(res) {
            this.abort();
            if(res.error != null) {
              this.onError(res.error, this);
            }

            if(typeof this.callback == "function") {
              this.callback(res, this);
            }
          },
          mozerror: function() {
            if(this.timeoutTimer != null) {
              clearTimeout(this.timeoutTimer);
            }
            var res = this.getEmptyRes();
            res.error = {Message:"Unknown",Type:"ConnectFailure",Status:0};
            this.endRequest(res);
          },
          doStateChange: function() {
            this.onStateChanged(this.xmlHttp.readyState, this);
            if(this.xmlHttp.readyState != 4 || !this.isRunning) {
              return;
            }
            this.duration = new Date().getTime() - this.__start;
            if(this.timeoutTimer != null) {
              clearTimeout(this.timeoutTimer);
            }
            var res = this.getEmptyRes();
            if(this.xmlHttp.status == 200 && this.xmlHttp.statusText == "OK") {
              res = this.createResponse(res);
            } else {
              res = this.createResponse(res, true);
              res.error = {Message:this.xmlHttp.statusText,Type:"ConnectFailure",Status:this.xmlHttp.status};
            }

            this.endRequest(res);
          },
          createResponse: function(r, noContent) {
            if(!noContent) {
              if(typeof(this.xmlHttp.responseText) == "unknown") {
                r.error = {Message: "XmlHttpRequest error reading property responseText.", Type: "XmlHttpRequestException"};
                return r;
              }

              var responseText = "" + this.xmlHttp.responseText;

              if(AjaxPro.cryptProvider != null && typeof AjaxPro.cryptProvider.decrypt == "function") {
                responseText = AjaxPro.cryptProvider.decrypt(responseText);
              }

              if(this.xmlHttp.getResponseHeader("Content-Type") == "text/xml") {
                r.value = this.xmlHttp.responseXML;
              } else {
                if(responseText != null && responseText.trim().length > 0) {
                  r.json = responseText;
                  var v = null;
                  v = AjaxPro.parse(responseText);
                  if(v != null) {
                    if(typeof v.value != "undefined") r.value = v.value;
                    else if(typeof v.error != "undefined") r.error = v.error;
                  }
                }
              }
            }
            /* if(this.xmlHttp.getResponseHeader("X-" + AjaxPro.ID + "-Cache") == "server") {
              r.isCached = true;
            } */
            return r;
          },
          timeout: function() {
            this.duration = new Date().getTime() - this.__start;
            var r = this.onTimeout(this.duration, this);
            if(typeof r == "undefined" || r != false) {
              this.abort();
            } else {
              this.timeoutTimer = setTimeout(this.timeout.bind(this), AjaxPro.timeoutPeriod);
            }
          },
          invoke: function(method, args, callback, context) {
            this.__start = new Date().getTime();

            // if(this.xmlHttp == null) {
              this.xmlHttp = new XMLHttpRequest();
            // }

            this.isRunning = true;
            this.method = method;
            this.args = args;
            this.callback = callback;
            this.context = context;

            var async = typeof(callback) == "function" && callback != AjaxPro.noOperation;

            if(async) {
              if(MS.Browser.isIE) {
                this.xmlHttp.onreadystatechange = this.doStateChange.bind(this);
              } else {
                this.xmlHttp.onload = this.doStateChange.bind(this);
                this.xmlHttp.onerror = this.mozerror.bind(this);
              }
              this.onLoading(true);
            }

            var json = AjaxPro.toJSON(args) + "";
            if(AjaxPro.cryptProvider != null && typeof AjaxPro.cryptProvider.encrypt == "function") {
              json = AjaxPro.cryptProvider.encrypt(json);
            }

            this.xmlHttp.open("POST", this.url, async);
            this.xmlHttp.setRequestHeader("Content-Type", "text/plain; charset=utf-8");
            this.xmlHttp.setRequestHeader("X-" + AjaxPro.ID + "-Method", method);

            if(AjaxPro.token != null && AjaxPro.token.length > 0) {
              this.xmlHttp.setRequestHeader("X-" + AjaxPro.ID + "-Token", AjaxPro.token);
            }

            /* if(!MS.Browser.isIE) {
              this.xmlHttp.setRequestHeader("Connection", "close");
            } */

            this.timeoutTimer = setTimeout(this.timeout.bind(this), AjaxPro.timeoutPeriod);

            try{ this.xmlHttp.send(json); }catch(e){} // IE offline exception

            if(!async) {
              return this.createResponse({error: null,value: null});
            }

            return true;
          }
        };

        AjaxPro.RequestQueue = function(conc) {
          this.queue = [];
          this.requests = [];
          this.timer = null;

          if(isNaN(conc)) { conc = 2; }

          for(var i=0; i<conc; i++) {   // max 2 http connections
            this.requests[i] = new AjaxPro.Request();
            this.requests[i].callback = function(res) {
              var r = res.context;
              res.context = r[3][1];

              r[3][0](res, this);
            };
            this.requests[i].callbackHandle = this.requests[i].callback.bind(this.requests[i]);
          }

          this.processHandle = this.process.bind(this);
        };

        AjaxPro.RequestQueue.prototype = {
          process: function() {
            this.timer = null;
            if(this.queue.length == 0) {
              return;
            }
            for(var i=0; i<this.requests.length && this.queue.length > 0; i++) {
              if(this.requests[i].isRunning == false) {
                var r = this.queue.shift();

                this.requests[i].url = r[0];
                this.requests[i].onLoading = r[3].length >2 && r[3][2] != null && typeof r[3][2] == "function" ? r[3][2] : AjaxPro.onLoading;
                this.requests[i].onError = r[3].length >3 && r[3][3] != null && typeof r[3][3] == "function" ? r[3][3] : AjaxPro.onError;
                this.requests[i].onTimeout = r[3].length >4 && r[3][4] != null && typeof r[3][4] == "function" ? r[3][4] : AjaxPro.onTimeout;
                this.requests[i].onStateChanged = r[3].length >5 && r[3][5] != null && typeof r[3][5] == "function" ? r[3][5] : AjaxPro.onStateChanged;

                this.requests[i].invoke(r[1], r[2], this.requests[i].callbackHandle, r);
                r = null;
              }
            }
            if(this.queue.length > 0 && this.timer == null) {
              this.timer = setTimeout(this.processHandle, 0);
            }
          },
          add: function(url, method, args, e) {
            this.queue.push([url, method, args, e]);
            if(this.timer == null) {
              this.timer = setTimeout(this.processHandle, 0);
            }
            // this.process();
          },
          abort: function() {
            this.queue.length = 0;
            if (this.timer != null) {
              clearTimeout(this.timer);
            }
            this.timer = null;
            for(var i=0; i<this.requests.length; i++) {
              if(this.requests[i].isRunning == true) {
                this.requests[i].abort();
              }
            }
          },
          dispose: function() {
            for(var i=0; i<this.requests.length; i++) {
              var r = this.requests[i];
              r.dispose();
            }
            this.requests.clear();
          }
        };

        AjaxPro.queue = new AjaxPro.RequestQueue(2);  // 2 http connections

        AjaxPro.AjaxClass = function(url) {
          this.url = url;
        };

        AjaxPro.AjaxClass.prototype = {
            invoke: function(method, args, e) {

                if (e != null) {
                    if (e.length != 6) {
                        for (; e.length < 6; ) { e.push(null); }
                    }
                    if (e[0] != null && typeof (e[0]) == "function") {
                        return AjaxPro.queue.add(this.url, method, args, e);
                    }
                }
                var r = new AjaxPro.Request();
                r.url = this.url;
                return r.invoke(method, args);
            }
        };
